package com.wanger.swc.aspect.appApiAspect;

import com.wanger.swc.exception.BusEx;
import com.wanger.swc.model.Result;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * @Author: wanger
 * @Date: 2024/11/3 17:46
 * @Description:
 */
@Slf4j
@Aspect
@Component
public class AppApiAspect {
    /**
     * 处理加了该注解的类或者方法，并检查方法的返回值是否为 Result，则进行包装，否则直接返回
     *
     * @param joinPoint 连接点
     * @return 包装后的数据对象
     */
    @Around("@within(com.wanger.swc.aspect.appApiAspect.AppApi) || @annotation(com.wanger.swc.aspect.appApiAspect.AppApi)")
    public Object aroundAppApiMethod(ProceedingJoinPoint joinPoint) throws Throwable {
        try {
            // 1. 获取被请求的api
            // 执行目标方法并获取返回值
            Object returnValue = joinPoint.proceed();

            // 2.判定是否需要封装
            if (decisionEncapsulation(joinPoint)) return new AppApiData(returnValue);
            else return returnValue;
        } catch (Throwable e) {
            // 3. 捕获异常并处理
            // 判断方法是否需要封装
            if (decisionEncapsulation(joinPoint)) return new AppApiData(handleException(e));
            else throw e;
        }
    }

    /**
     * 判定是否需要封装；
     * 允许封装的情况：1.方法返回值为Result，2.符合条件1并且方法上面没有加AppApi注解，3.符合条件1并且方法上面的注解允许封装
     *
     * @param joinPoint 代理对象
     * @return true：需要封装，false：不需要封装
     */
    private static boolean decisionEncapsulation(ProceedingJoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Class<?> returnType = method.getReturnType();
        //检查类型
        if (Result.class.equals(returnType)) {
            //1.如果是类上面加的注解进入的aop，则检查方法上面是否有注解，
            AppApi appApi = method.getAnnotation(AppApi.class);
            //1.1.没有则返回true，进入了aop但注解又是空的，标识加到类上面，默认允许封装
            if (appApi == null) return true;
            //1.2.有则检查是否允许封装，允许则返回true，不允许则返回false
            return appApi.enabled();
        } else return false;
    }


    /**
     * 处理异常情况
     *
     * @param e 异常对象
     * @return 返回 Result 对象
     */
    private Result<String> handleException(Throwable e) {
        // 模拟全局异常处理逻辑
        if (e instanceof BusEx) {
            log.warn("业务异常: {}", e.getMessage(), e);
            return Result.error(500, ((BusEx) e).getMsg());
        }
        // 默认情况
        log.error("系统异常:{}", e.getMessage(), e);
        return Result.error500();
    }

    /**
     * app请求统一返回对象
     */
    @Getter
    public static class AppApiData extends Result<Object> {
        private static final long serialVersionUID = -2349659052015925083L;
        /**
         * 返回数据
         */
        private final Object dataV;

        public AppApiData(Object dataV) {
            super(HttpStatus.OK.value(), "请求成功", null);
            this.dataV = dataV;
        }

    }
}
